home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / contrib / russo / popen_ioe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-25  |  5.5 KB  |  189 lines

  1. /*
  2.  * Copyright (c) 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software written by Ken Arnold and
  6.  * published in UNIX Review, Vol. 6, No. 8.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that: (1) source distributions retain this entire copyright
  10.  * notice and comment, and (2) distributions including binaries display
  11.  * the following acknowledgement:  ``This product includes software
  12.  * developed by the University of California, Berkeley and its contributors''
  13.  * in the documentation or other materials provided with the distribution
  14.  * and in all advertising materials mentioning features or use of this
  15.  * software. Neither the name of the University nor the names of its
  16.  * contributors may be used to endorse or promote products derived
  17.  * from this software without specific prior written permission.
  18.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21.  */
  22.  
  23. #if defined(LIBC_SCCS) && !defined(lint)
  24. static char sccsid[] = "@(#)popen.c    5.14 (Berkeley) 6/1/90";
  25. #endif /* LIBC_SCCS and not lint */
  26.  
  27. #include <sys/param.h>
  28. #define _BSD_SIGNALS        /* for IRIX, to use BSD signals */
  29. #include <sys/signal.h>
  30. #include <sys/wait.h>
  31. #include <errno.h>
  32. #include <stdio.h>
  33. #include <unistd.h>
  34. int bzero(void *, int); /* this isn't in a header file !? */
  35. #include <paths.h>
  36. #include <string.h>
  37. #include <stdlib.h>
  38.  
  39. static pid_t *pids;
  40.  
  41. /*
  42.  * Original popen() code extended to open multiple pipes to a process
  43.  *
  44.  * By Kevin Russo
  45.  *    SFA, Inc/US Naval Research Lab, Code 5133
  46.  *    March 14, 1991
  47.  *
  48.  * Calling sequence:
  49.  *    FILE (*popen_ioe(const char *command, const char *type))[3];
  50.  *    FILE ** popen_ioe(const char *command, const char *type);
  51.  *
  52.  *    Arguments:
  53.  *    type    - a string containing any of the letters "rwe"
  54.  *    command - a shell command
  55.  *
  56.  *    Returns:
  57.  *    FILE **ptr;
  58.  *
  59.  *    ptr[0] is a FILE pointer to the command's stdin
  60.  *    ptr[1] is a FILE pointer to the command's stdout
  61.  *    ptr[2] is a FILE pointer to the command's stderr
  62.  *
  63.  *    If a connection was not requested, that ptr is NULL.
  64.  *    type may contain r and/or w and/or e, but must contain one of them.
  65.  */
  66.  
  67. FILE **
  68. popen_ioe(const char *program, const char *type)
  69. {
  70. FILE **iop;
  71. int pdes[2], fds, pid;
  72. int pdes2[2], pdes3[2];
  73. int in, out, err;
  74.  
  75.     if (pids == NULL) {
  76.         if ((fds = getdtablesize()) <= 0)
  77.             return (NULL);
  78.         if((pids = (pid_t *)malloc((u_int)(fds * sizeof(int)))) == NULL)
  79.             return (NULL);
  80.         bzero((void *)pids, fds * sizeof(pid_t));
  81.     }
  82.     if ((iop = (FILE **) malloc(3 * sizeof(FILE **))) == NULL)
  83.         return (NULL);
  84.     bzero((void *)iop, 3 * sizeof(FILE **));
  85.  
  86.     in = (int) strchr(type, 'r');
  87.     out = (int) strchr(type, 'w');
  88.     err = (int) strchr(type, 'e');
  89.     if(!in && !out && !err)        /* have to set one of them */
  90.         return (NULL);
  91.  
  92.     if(in && pipe(pdes) < 0)
  93.         return (NULL);
  94.     if(out && pipe(pdes2) < 0)
  95.         return (NULL);
  96.     if(err && pipe(pdes3) < 0)
  97.         return (NULL);
  98.     /*
  99.     if (pipe(pdes) < 0 || pipe(pdes2) < 0 || pipe(pdes3) < 0)
  100.         return (NULL);
  101.     */
  102.     switch (pid = fork()) {
  103.     case -1:            /* error */
  104.         if (in)  { (void) close(pdes[0]);  (void) close(pdes[1]); }
  105.         if (out) { (void) close(pdes2[0]); (void) close(pdes2[1]); }
  106.         if (err) { (void) close(pdes3[0]); (void) close(pdes3[1]); }
  107.         return (NULL);
  108.         /* NOTREACHED */
  109.     case 0:                /* child */
  110.         if (in) {
  111.                     if (pdes[1] != STDOUT_FILENO) {
  112.                             (void) dup2(pdes[1], STDOUT_FILENO);
  113.                             (void) close(pdes[1]);
  114.                     }
  115.                     (void) close(pdes[0]);
  116.         }
  117.         if (out) {
  118.                     if (pdes2[0] != STDIN_FILENO) {
  119.                             (void) dup2(pdes2[0], STDIN_FILENO);
  120.                             (void) close(pdes2[0]);
  121.                     }
  122.                     (void) close(pdes2[1]);
  123.         }
  124.         if (err) {
  125.                     if (pdes3[1] != STDERR_FILENO) {
  126.                             (void) dup2(pdes3[1], STDERR_FILENO);
  127.                             (void) close(pdes3[1]);
  128.                     }
  129.                     (void) close(pdes3[0]);
  130.         }
  131.         execl(_PATH_BSHELL, "sh", "-c", program, NULL);
  132.         _exit(127);
  133.         /* NOTREACHED */
  134.     }
  135.     /* parent; assume fdopen can't fail...  */
  136.     if (in) {
  137.         iop[0] = fdopen(pdes[0], "r");
  138.         (void) close(pdes[1]);
  139.         pids[fileno(iop[0])] = pid;
  140.     }
  141.     if(out) {
  142.         iop[1] = fdopen(pdes2[1], "w");
  143.         (void) close(pdes2[0]);
  144.         pids[fileno(iop[1])] = pid;
  145.     }
  146.     if(err) {
  147.         iop[2] = fdopen(pdes3[0], "r");
  148.         (void) close(pdes3[1]);
  149.         pids[fileno(iop[2])] = pid;
  150.     }
  151.     return (iop);
  152. }
  153.  
  154. int
  155. pclose_ioe(FILE *iop[3])
  156. {
  157.     register int fdes, fdes1, fdes2, fdes3;
  158.     int omask;
  159.     /* union wait pstat;*/
  160.     int pstat;
  161.     pid_t pid;
  162.  
  163.     /*
  164.      * pclose returns -1 if stream is not associated with a
  165.      * `popened' command, if already `pclosed', or waitpid
  166.      * returns an error.
  167.      */
  168.     if (pids == NULL)
  169.         return (-1);
  170.     if (iop[0] != 0 && pids[fdes1 = fileno(iop[0])] == 0 ||
  171.         iop[1] != 0 && pids[fdes2 = fileno(iop[1])] == 0 ||
  172.         iop[2] != 0 && pids[fdes3 = fileno(iop[2])] == 0)
  173.         return (-1);
  174.     /* any fdes will do since all the pids are the same */
  175.     if(! iop[0]) { (void) fclose(iop[0]); fdes = fdes1; }
  176.     if(! iop[1]) { (void) fclose(iop[1]); fdes = fdes2; }
  177.     if(! iop[2]) { (void) fclose(iop[2]); fdes = fdes3; }
  178.     omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
  179.     do {
  180.         pid = waitpid(pids[fdes], &pstat, 0);
  181.     } while (pid == -1 && errno == EINTR);
  182.     (void) sigsetmask(omask);
  183.     pids[fdes1] = 0;
  184.     pids[fdes2] = 0;
  185.     pids[fdes3] = 0;
  186.     /*return (pid == -1 ? -1 : pstat.w_status);*/
  187.     return (pid == -1 ? -1 : pstat);
  188. }
  189.